package com.flyqiu.common.bean;

import com.baomidou.mybatisplus.extension.service.IService;
import com.flyqiu.common.clazz.FlyQiuClassTools;
import org.mybatis.spring.SqlSessionTemplate;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * 简单bean管理器实现类，用于管理和获取bean实例
 */
public class FlyQiuSimpleBeanManage implements FlyQiuBeanManage {

    // 存储bean实例的Map，key为bean类类型，value为bean实例
    private static final Map<Class<?>, Object> serviceMap = new HashMap<>();

    private final SqlSessionTemplate sqlSession; // MyBatis SqlSessionTemplate实例

    /**
     * 构造函数
     *
     * @param sqlSession MyBatis的SqlSessionTemplate实例
     */
    public FlyQiuSimpleBeanManage(SqlSessionTemplate sqlSession) {
        this.sqlSession = sqlSession;
    }

    /**
     * 添加bean对象到管理器中
     *
     * @param clazz     bean的类类型
     * @param clazzInst bean的实例
     * @param <T>       bean的类型
     */
    @Override
    public <T> void addBean(Class<T> clazz, T clazzInst) {
        serviceMap.put(clazz, clazzInst);
    }

    /**
     * 添加bean对象到管理器中，通过实例自动获取其类型
     *
     * @param clazzInst bean的实例
     */
    @Override
    public void addBean(Object clazzInst) {
        serviceMap.put(clazzInst.getClass(), clazzInst);
    }

    /**
     * 检查bean实例是否已存储在管理器中
     *
     * @param clazz bean的类型
     * @return 如果bean已存在，则返回true；否则返回false
     */
    @Override
    public boolean hasBean(Class<?> clazz) {
        if (serviceMap.containsKey(clazz)) {
            return true;
        }
        Object instance = getBeanInstanceByParentClass(clazz);
        return instance != null;
    }

    /**
     * 根据类型获取bean实例
     *
     * @param clazz 类型
     * @param <T>   bean的类型
     * @return bean的实例
     * @throws RuntimeException 如果无法找到对应的bean实例，则抛出异常
     */
    @Override
    @SuppressWarnings("unchecked")
    public <T> T getBean(Class<T> clazz) {
        if (serviceMap.containsKey(clazz)) {
            return (T) serviceMap.get(clazz);
        }
        T beanInstance = getBeanInstanceByParentClass(clazz);
        if (beanInstance == null) {
            throw new RuntimeException("No bean instance of this type " + clazz.getName() + " was found");
        }
        return beanInstance;
    }

    /**
     * 根据类型获取所有bean实例的Map
     *
     * @param clazz bean的基类
     * @param <T>   bean的基类类型
     * @return 所有bean实例的Map，key为bean类的简单名称，value为bean实例
     */
    @Override
    public <T> Map<String, T> getBeanMap(Class<T> clazz) {
        return getBeansInstanceByParentClass(clazz);
    }

    /**
     * 根据基类获取所有子类的bean实例Map
     *
     * @param clazz 子类的基类
     * @param <T>   子类的基类类型
     * @return 所有子类bean实例的Map，key为子类的简单名称，value为子类实例
     */
    private <T> Map<String, T> getBeansInstanceByParentClass(Class<T> clazz) {
        Set<Map.Entry<Class<?>, Object>> entries = serviceMap.entrySet();
        Map<String, T> resultMap = new HashMap<>();
        for (Map.Entry<Class<?>, Object> next : entries) {
            Class<?> result = next.getKey();
            if (FlyQiuClassTools.isForm(clazz, result)) {
                Object value = next.getValue();
                serviceMap.put(clazz, value);
                //noinspection unchecked
                resultMap.put(clazz.getSimpleName(), (T) value);
            }
        }
        return resultMap;
    }

    /**
     * 根据类型从serviceMap中获取bean实例，如果未找到，则尝试通过反射创建实例
     *
     * @param clazz 类型
     * @param <T>   bean的类型
     * @return bean的实例
     */
    @SuppressWarnings("unchecked")
    private <T> T getBeanInstanceByParentClass(Class<T> clazz) {
        Set<Map.Entry<Class<?>, Object>> entries = serviceMap.entrySet();
        for (Map.Entry<Class<?>, Object> next : entries) {
            Class<?> result = next.getKey();
            if (FlyQiuClassTools.isForm(clazz, result)) {
                Object value = next.getValue();
                serviceMap.put(clazz, value);
                return (T) value;
            }
        }
        return null;
    }

    /**
     * 添加服务接口实现到管理器
     *
     * @param clazz   服务接口类
     * @param service 服务接口的实现
     * @param <T>     服务接口类型
     */
    public <T extends IService<?>> void addService(Class<T> clazz, T service) {
        serviceMap.put(clazz, service);
    }

    /**
     * 获取服务接口实例
     *
     * @param clazz 服务接口类
     * @param <T>   服务接口类型
     * @return 服务接口的实例
     * @throws RuntimeException 如果无法找到对应的服务接口实例，则抛出异常
     */
    @SuppressWarnings("unchecked")
    public <T extends IService<?>> T getService(Class<T> clazz) {
        T result = (T) serviceMap.get(clazz);
        if (result == null) {
            result = getBeanInstanceByParentClass(clazz);
        }
        if (result == null) {
            throw new NullPointerException("No bean instance of this type " + clazz.getName() + " was found");
        }

        return result;
    }

    /**
     * 获取MyBatis Mapper接口实例
     *
     * @param clazz Mapper接口类
     * @param <T>   Mapper接口类型
     * @return Mapper接口的实例
     */
    @Override
    @SuppressWarnings("unchecked")
    public <T> T getMapper(Class<T> clazz) {
        T result = (T) serviceMap.get(clazz);
        if (result == null) {
            result = getBeanInstanceByParentClass(clazz);
        }
        if (result != null) return result;
        T mapper = sqlSession.getMapper(clazz);
        serviceMap.put(clazz, mapper);
        return mapper;
    }

    @Override
    public void autowire(Object bean) {
        throw new RuntimeException("该方法暂无实现无法完成自动注入");
    }


}
